﻿using System;
using System.Collections.Generic;
using System.Xml;
using SSP.Api.Interfaces;
using SSP.Api.Options;

namespace SSP.Api
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class DirectorContent : DirectorWrapper, IDeserializer
    {
        private Dictionary<string, DirectorImage> _customImages;

        /// <summary>
        /// Initializes a new instance of the <see cref="DirectorContent"/> class.
        /// </summary>
        /// <param name="parent">The parent.</param>
        public DirectorContent(Director parent) : base(parent)
        {
        }

        /// <summary>
        /// The content's unique ID in the database.
        /// </summary>
        /// <value>The id.</value>
        public int Id { get; set; }

        /// <summary>
        /// The Album ID this content belongs to.
        /// </summary>
        /// <value>The album id.</value>
        public int AlbumId { get; set; }

        /// <summary>
        /// The content's file name.
        /// </summary>
        /// <value>The SRC.</value>
        public string Source { get; set; }

        /// <summary>
        /// The content's title as entered into Director.
        /// </summary>
        /// <value>The title.</value>
        public string Title { get; set; }

        /// <summary>
        /// The content's caption as entered into Director.
        /// </summary>
        /// <value>The caption.</value>
        public string Caption { get; set; }

        /// <summary>
        /// Tags assigned to the content in Director.
        /// </summary>
        /// <value>The tags.</value>
        public string Tags { get; set; }

        /// <summary>
        /// The content's link as entered into Director.
        /// </summary>
        /// <value>The link.</value>
        public string Link { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="DirectorContent"/> is active.
        /// </summary>
        /// <value><c>true</c> if active; otherwise, <c>false</c>.</value>
        public bool Active { get; set; }

        /// <summary>
        /// The full HTTP path to the album's audio file, if set.
        /// </summary>
        /// <value>The audio.</value>
        public string Audio { get; set; }

        /// <summary>
        /// Gets or sets the audio_caption.
        /// </summary>
        /// <value>The audio_caption.</value>
        public string AudioCaption { get; set; }

        /// <summary>
        /// The numerical position of the content in the album's order.
        /// </summary>
        /// <value>The seq.</value>
        public int Sequence { get; set; }

        /// <summary>
        /// If set, how long the content should pause.
        /// </summary>
        /// <value>The pause.</value>
        public int Pause { get; set; }

        /// <summary>
        /// Whether the link should open in a new window (true) or the same window (false).
        /// </summary>
        /// <value>The target.</value>
        public bool Target { get; set; }

        /// <summary>
        /// The date and time the content was last updated.
        /// </summary>
        /// <value>The modified.</value>
        public DateTime Modified { get; set; }

        /// <summary>
        /// The date and time the content was created.
        /// </summary>
        /// <value>The created.</value>
        public DateTime Created { get; set; }

        /// <summary>
        /// The date and time the content was captured, as embedded by the camera.
        /// </summary>
        /// <value>The captured on.</value>
        public DateTime Captured { get; set; }

        /// <summary>
        /// The size of the originally uploaded content.
        /// </summary>
        /// <value>The filesize.</value>
        public int Filesize { get; set; }

        /// <summary>
        /// User object containing information on the user who created the content.
        /// </summary>
        /// <value>The creator.</value>
        public DirectorUser Creator { get; set; }

        /// <summary>
        /// User object containing information on the user who last updated the content.
        /// </summary>
        /// <value>The updater.</value>
        public DirectorUser Updater { get; set; }

        /// <summary>
        /// The full HTTP path to the album's preview.
        /// </summary>
        /// <value>The preview.</value>
        public string Preview { get; set; }

        /// <summary>
        /// Contains three properties: url, width and height.
        /// </summary>
        /// <value>The original.</value>
        public DirectorImage Original { get; set; }

        /// <summary>
        /// Exif data from the content (see EXIF section below).
        /// </summary>
        /// <value>The exif.</value>
        public EXIF EXIF { get; set; }

        /// <summary>
        /// IPTC data from the content (see IPTC section below).
        /// </summary>
        /// <value>The iptc.</value>
        public IPTC IPTC { get; set; }

        /// <summary>
        /// If custom sizes have been specified, they will be in the dictionary keyed by the name specified.
        /// </summary>
        /// <value>The custom images.</value>
        public Dictionary<String, DirectorImage> CustomImages
        {
            get
            {
                if (_customImages == null)
                {
                    _customImages = new Dictionary<string, DirectorImage>();
                }
                return _customImages;
            }
        }

        #region IDeserializer Members

        /// <summary>
        /// Gets or sets the <see cref="System.String"/> with the specified property name.
        /// </summary>
        /// <value></value>
        public string this[string propertyName]
        {
            get { return _sDict[propertyName]; }
            set { _sDict[propertyName] = value; }
        }

        private readonly Dictionary<string, string> _sDict = new Dictionary<string, string>();

        /// <summary>
        /// Deserializes from an XmlReader and sets the object's properties.
        /// </summary>
        /// <param name="reader">The reader.</param>
        public void DeserializeFromReader(XmlReader reader)
        {
            // Start to use the reader.
            reader.Read();

            // Read all elements
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                switch (reader.Name)
                {
                    case "id":
                        Id = reader.ReadElementContentAsInt();
                        break;
                    case "album_id":
                        AlbumId = reader.ReadElementContentAsInt();
                        break;
                    case "src":
                        Source = reader.ReadElementContentAsString();
                        break;
                    case "title":
                        Title = reader.ReadElementContentAsString();
                        break;
                    case "caption":
                        Caption = reader.ReadElementContentAsString();
                        break;
                    case "tags":
                        Tags = reader.ReadElementContentAsString();
                        break;
                    case "link":
                        Link = reader.ReadElementContentAsString();
                        break;
                    case "audio":
                        Audio = reader.ReadElementContentAsString();
                        break;
                    case "audio_caption":
                        AudioCaption = reader.ReadElementContentAsString();
                        break;
                    case "preview":
                        Preview = reader.ReadElementContentAsString();
                        break;
                    case "active":
                        Active = reader.ReadElementContentAsBoolean();
                        break;
                    case "seq":
                        Sequence = convertToInt(reader.ReadElementContentAsString());
                        break;
                    case "pause":
                        Pause = convertToInt(reader.ReadElementContentAsString());
                        break;
                    case "target":
                        Target = reader.ReadElementContentAsBoolean();
                        break;
                    case "modified":
                        Modified = DirectorUtils.ConvertFromUnixTimestamp(reader.ReadElementContentAsString());
                        break;
                    case "created":
                        Created = DirectorUtils.ConvertFromUnixTimestamp(reader.ReadElementContentAsString());
                        break;
                    case "captured_on":
                        Captured = DirectorUtils.ConvertFromUnixTimestamp(reader.ReadElementContentAsString());
                        break;
                    case "filesize":
                        Filesize = reader.ReadElementContentAsInt();
                        break;
                    case "creator":
                        Creator = new DirectorUser(Parent);
                        Creator.DeserializeFromReader(reader);
                        break;
                    case "updater":
                        Updater = new DirectorUser(Parent);
                        Updater.DeserializeFromReader(reader);
                        break;
                    case "original":
                        Original = new DirectorImage(Parent);
                        Original.DeserializeFromReader(reader);
                        break;
                    case "exif":
                        EXIF = new EXIF();
                        EXIF.DeserializeFromReader(reader);
                        break;
                    case "iptc":
                        IPTC = new IPTC();
                        IPTC.DeserializeFromReader(reader);
                        break;
                    default:
                        try
                        {
                            var cImageName = reader.Name;
                            var custImage = new DirectorImage(Parent);
                            custImage.DeserializeFromReader(reader);
                            CustomImages.Add(cImageName, custImage);
                        }
                        catch
                        {
                            System.Diagnostics.Trace.WriteLine("Unhandled xml element name '" + reader.Name + "'.");
                            _sDict[reader.Name] = reader.ReadElementContentAsString();
                            break;
                        }
                        break;
                }
                reader.MoveToContent();
            }

            // Extremely important to read the node to its end.
            // next call of the reader methods will crash if not called.
            reader.ReadEndElement();
        }

        #endregion

        /// <summary>
        /// Gets the specified id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public DirectorContent Get(int id)
        {
            Parent.Post.Add("data[content_id]=" + id);
            DirectorResponse response = Parent.send("get_content", "get_content_" + id);
            return response.Content;
        }

        /// <summary>
        /// Alls the specified options.
        /// </summary>
        /// <param name="options">The options.</param>
        /// <returns></returns>
        public DirectorContent[] All(ContentOptions options)
        {
            string tail = "get_content_list_";
            if (options.limit > 0)
            {
                Parent.Post.Add("data[limit]=" + options.limit);
            }
            if (options.only_images)
            {
                Parent.Post.Add("data[only_images]=1");
            }

            if (options.only_active)
            {
                Parent.Post.Add("data[only_active]=1");
            }
            else
            {
                Parent.Post.Add("data[only_active]=0");
            }

            bool all;
            if (options.tags != null && options.tags.criteria == Criteria.all)
            {
                all = true;
            }
            else
            {
                all = false;
            }
            tail += String.Join("_", new[] { options.limit.ToString(), (options.only_images ? 1 : 0).ToString(), (options.only_active ? 1 : 0).ToString(), (all ? 1 : 0).ToString(), options.sort_on, options.sort_direction.ToString() });
            if (options.scope != null)
            {
                tail += "_" + options.scope.method + "_" + options.scope.id;
                Parent.Post.Add("data[scope]=" + options.scope.method);
                Parent.Post.Add("data[scope_id]=" + options.scope.id);
            }
            Parent.Post.Add("data[tags]=" + options.tags.QueryString);
            Parent.Post.Add("data[tags_exclusive]=" + BoolToInt(all));
            Parent.Post.Add("data[sort_on]=" + options.sort_on);
            Parent.Post.Add("data[sort_direction]=" + options.sort_direction);
            DirectorResponse response = Parent.send("get_content_list", tail);
            return response.Contents;
        }
    }
}